package com.howie.hmvc;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.howie.hmvc.handler.IInvokeHandler;
import com.howie.hmvc.handler.IUploadProgressHandler;
import com.howie.hmvc.request.MultipartRequest;
import com.howie.hmvc.scanner.ActionInfo;
import com.howie.hmvc.scanner.ControllerScanner;

/**
 * 框架核心过滤器
 * @author dhz
 */
public class DispatcherFilter implements Filter {

	private static final Logger LOG = Logger.getLogger(DispatcherFilter.class);
	private Map<String,ActionInfo> actions;
	private IInvokeHandler invokeHandler;
	private Class<IUploadProgressHandler> uploadProgressHandler;
	
	@Override
	public void destroy() {
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse resp,FilterChain chain)throws IOException,ServletException {
		HttpServletRequest request = (HttpServletRequest)req;
		HttpServletResponse response = (HttpServletResponse)resp;
		
		request.setCharacterEncoding("UTF-8");
		response.setCharacterEncoding("UTF-8");
		if(!invoke(request,response)){
			chain.doFilter(req,resp);
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public void init(FilterConfig config) throws ServletException {
		try {
			//扫描并注册controller
			String controllerPackage = config.getInitParameter("controllerPackage");
			actions = ControllerScanner.scanControllersFromPackges(controllerPackage.split(","));
			//获取事件实现类
			String invokeHandlerPath = config.getInitParameter("invokeHandler");
			if(StringUtils.isNotBlank(invokeHandlerPath)){
				invokeHandler = (IInvokeHandler)Class.forName(invokeHandlerPath).newInstance();
			}
			String uploadProgress = config.getInitParameter("uploadProgress");
			if(StringUtils.isNotBlank(uploadProgress)){
				uploadProgressHandler = (Class<IUploadProgressHandler>)Class.forName(uploadProgress);
			}
			//随系统启动的任务
			startTask(config);
		} catch (Exception e) {
			LOG.error("系统初始化异常",e);
			System.exit(0);
		}
	}
	
	/*
	 * 调用Controller
	 * @param request
	 * @param response
	 * @return
	 */
	private boolean invoke(HttpServletRequest request,HttpServletResponse response){
		String uri = request.getRequestURI().substring(request.getContextPath().length());
		int lastIndexSep = uri.lastIndexOf("/");
		if(uri.endsWith("/")){
			uri += "index";
		}else{
			int index = uri.indexOf(".",lastIndexSep);
			if(index != -1){
				uri = uri.substring(0,index);
			}
		}
		ActionInfo action = actions.get(uri);
		if(action != null){
			Object result = null;
			Throwable exp = null;
			try {
				//multipart提交要特殊处理
				String type = request.getHeader("Content-Type");
				if(type != null && type.contains("multipart/form-data")){
					request = new MultipartRequest(request,uploadProgressHandler);
				}
				Object[] params = action.assemParam(request,response);
				if(invokeHandler != null){
					if(!invokeHandler.beforeInvoke(action.getMethod(),request,response)){
						LOG.debug("invokeHandler终止了请求");
						return true;
					}
				}
				result = action.getMethod().invoke(action.getDoInstance(),params);
			} catch (Throwable e) {
				while(e instanceof InvocationTargetException){
					e = ((InvocationTargetException)e).getTargetException();
				}
				exp = e;
			} finally {
				if(invokeHandler != null){
					try {
						invokeHandler.afterInvoke(action.getMethod(),exp,result,request,response);
					} catch (Throwable e) {
						throw new RuntimeException(e);
					}
				}
			}
			return true;
		}
		return false;
	}
	
	/*
	 * 启动任务
	 * @param tasks
	 * @throws Exception
	 */
	private void startTask(FilterConfig config)throws Exception{
		String tasks = config.getInitParameter("tasks");
		if(!StringUtils.isBlank(tasks)){
			ServletContext cxt = config.getServletContext();
			String[] paths = tasks.split(",");
			for(String path : paths){
				String[] entry = path.split(":");
				LOG.debug("启动任务：" + entry[0]);
				Class<?> clazz = Class.forName(entry[0]);
				clazz.getMethod(entry[1],ServletContext.class).invoke(clazz,cxt);
			}
		}
	}
	
}
